using System;
using System.Drawing;

namespace Shrapnel
{
    public class ViewState
    {
        /// <summary>
        /// The zoom factory of this view state.
        /// </summary>
        private float zoomFactor = 1.0f;

        /// <summary>
        /// The offset of the view.
        /// </summary>
        private PointF offset = PointF.Empty;

		/// <summary>
		/// The size of our viewport in which this view is shown
		/// </summary>
		private SizeF viewportSize = SizeF.Empty;

        /// <summary>
        /// Gets or sets the zoom factory of this view state.
        /// </summary>
        public float ZoomFactor
        {
            get { return zoomFactor; }
            set { zoomFactor = value; }
        }

        /// <summary>
        /// Gets or sets the offset of the view.
        /// </summary>
        public PointF Offset
        {
            get { return offset; }
            set { offset = value; }
        }

		/// <summary>
		/// The size of our viewport in which this view is shown
		/// </summary>
		public SizeF ViewportSize
		{
			get { return viewportSize; }
			set { viewportSize = value; }
		}


		/// <summary>
		/// Default constructor
		/// </summary>
		public ViewState()
		{
		}

		/// <summary>
		/// Copy constructor
		/// </summary>
		/// <param name="other">The source viewstate to copy from</param>
		public ViewState(ViewState other)
		{
			this.offset = other.offset;
			this.zoomFactor = other.zoomFactor;
		}


        /// <summary>
        /// Converts the given world space position to screen space coordinates.
        /// </summary>
        /// <param name="position">The position to convert.</param>
        /// <returns>Returns the converted position.</returns>
        public PointF WorldToScreen(PointF position)
        {
            return new PointF(position.X * zoomFactor + offset.X, position.Y * zoomFactor + offset.Y);
        }

        /// <summary>
        /// Converts the given screen space position to world space coordinates.
        /// </summary>
        /// <param name="position">The position to convert.</param>
        /// <returns>Returns the converted position.</returns>
        public PointF ScreenToWorld(PointF position)
        {
            return new PointF((position.X - offset.X) / zoomFactor, (position.Y - offset.Y) / zoomFactor);
        }

        /// <summary>
        /// Converts the given world space rectangle to screen space coordinates.
        /// </summary>
        /// <param name="position">The rectangle to convert.</param>
        /// <returns>Returns the converted rectangle.</returns>
        public RectangleF WorldToScreen(RectangleF worldRect)
        {
			return new RectangleF(
				worldRect.X * zoomFactor + offset.X,
				worldRect.Y * zoomFactor + offset.Y,
				worldRect.Width * zoomFactor,
				worldRect.Height * zoomFactor);
        }

        /// <summary>
        /// Converts the given screen space rectangle to world space coordinates.
        /// </summary>
        /// <param name="position">The position to rectangle.</param>
        /// <returns>Returns the converted rectangle.</returns>
        public RectangleF ScreenToWorld(RectangleF screenRect)
        {
			return new RectangleF(
				(screenRect.X - offset.X) / zoomFactor,
				(screenRect.Y - offset.Y) / zoomFactor,
				screenRect.Width / zoomFactor,
				screenRect.Height / zoomFactor);
        }


		/// <summary>
		/// Calculate a worldspace bounding box for our view
		/// </summary>
		/// <returns></returns>
		public BoundingBox GetWorldBoundingBox()
		{
			RectangleF screen = new RectangleF(new PointF(0, 0), viewportSize);
			RectangleF world = ScreenToWorld(screen);

			return new BoundingBox(world);
		}
    }
}
